package com.lfc.flowable.service.impl;

import com.lfc.flowable.domian.FlowInfo;
import com.lfc.flowable.domian.LeaveApply;
import com.lfc.flowable.domian.TableDataInfo;
import com.lfc.flowable.domian.dto.TaskInfo;
import com.lfc.flowable.service.FlowableService;
import com.lfc.flowable.service.LeaveApplyService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 流程定义实现类
 */
@Slf4j
@Service
public class FlowableServiceImpl implements FlowableService {

    @Resource
    private ProcessEngine processEngine;

    @Resource
    LeaveApplyService leaveApplyService;

    @Override
    public TableDataInfo myList(TaskInfo param) {
        TaskQuery condition = processEngine.getTaskService().createTaskQuery();
        if (StringUtils.isNotEmpty(param.getTaskName())) {
            condition.taskName(param.getTaskName());
        }
        if (StringUtils.isNotEmpty(param.getProcessName())) {
            condition.processDefinitionName(param.getProcessName());
        }
        if (StringUtils.isNotEmpty(param.getAssignee())) {
            condition.taskAssignee(param.getAssignee());
        }
        // 过滤掉流程挂起的待办任务
        int total = condition.active().orderByTaskCreateTime().desc().list().size();
        int start = (param.getPageNum() - 1) * param.getPageSize();
        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
        List<TaskInfo> tasks = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        taskList.stream().forEach(a -> {
            ProcessInstance process = processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
            TaskInfo info = new TaskInfo();
            info.setAssignee(a.getAssignee());
            info.setBusinessKey(process.getBusinessKey());
            info.setCreateTime(sdf.format(a.getCreateTime()));
            info.setTaskName(a.getName());
            info.setExecutionId(a.getExecutionId());
            info.setProcessInstanceId(a.getProcessInstanceId());
            info.setProcessName(process.getProcessDefinitionName());

            //流程变量（含业务ID）
            LeaveApply leaveApply = leaveApplyService.getLeaveApply(process.getBusinessKey());
            info.setStarter(leaveApply.getUserId());
            info.setStartTime(sdf.format(process.getStartTime()));
            info.setTaskId(a.getId());
//            String formKey = processEngine.getFormService().getTaskFormData(a.getId()).getFormKey();
//            info.setFormKey(formKey);
            tasks.add(info);
        });
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(0);
        rspData.setRows(tasks);
        rspData.setTotal(total);
        return rspData;
    }

    @Override
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processInstanceId) throws IOException {
        ProcessInstance pi = processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        //流程走完的不显示图
//        if (Objects.isNull(pi))
//            return;
        Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = processEngine.getRuntimeService()
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new LinkedList<>();
        List<String> flowList = new LinkedList<>();
        for (Execution exe : executions) {
            List<String> ids = processEngine.getRuntimeService().getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }
        //获取流程图
        renderFlow(httpServletResponse, activityIds, flowList, pi.getProcessDefinitionId());
    }

    @Override
    public List<TaskInfo> history(String taskId) {
        String processInstanceId = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        return historyByProcessInstanceId(processInstanceId);
    }

    @Override
    public List<TaskInfo> historyByProcessInstanceId(String processInstanceId) {
        List<HistoricActivityInstance> history = processEngine.getHistoryService()
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc()
                .list();
        List<TaskInfo> infos = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        history.stream().forEach(h -> {
            TaskInfo info = new TaskInfo();
            info.setProcessInstanceId(h.getProcessInstanceId());
            info.setTaskId(h.getTaskId());
            info.setExecutionId(h.getExecutionId());
            info.setStartTime(sdf.format(h.getStartTime()));
            if (h.getEndTime() != null) {
                info.setEndTime(sdf.format(h.getEndTime()));
            }
            //处理开始事件节点
            if ("startEvent".equals(h.getActivityType())) {
                info.setTaskName("流程发起");
                info.setAssignee(h.getAssignee());
            } else if ("userTask".equals(h.getActivityType())) {
                //用户任务处理逻辑
                info.setTaskName(h.getActivityName());
                info.setAssignee(h.getAssignee());
            } else {
                return;
            }

            List<Comment> comments = processEngine.getTaskService().getTaskComments(h.getTaskId());
            if (comments.size() > 0) {
                info.setComment(comments.get(0).getFullMessage());
            }
            infos.add(info);
        });
        return infos;
    }

    @Override
    public TableDataInfo listHistoryProcess(String businessKey, String name, Integer pageSize, Integer pageNum) {
        int total = processEngine.getHistoryService().createHistoricProcessInstanceQuery().orderByProcessInstanceStartTime().desc().list().size();
        int start = (pageNum - 1) * pageSize;
        HistoricProcessInstanceQuery condition = processEngine.getHistoryService().createHistoricProcessInstanceQuery();
        if (StringUtils.isNotEmpty(businessKey)) {
            condition.processInstanceBusinessKey(businessKey);
        }
        if (StringUtils.isNotEmpty(name)) {
            condition.processDefinitionName(name);
        }
        List<HistoricProcessInstance> processList = condition.orderByProcessInstanceStartTime().desc().listPage(start, pageSize);
        List<FlowInfo> flows = new ArrayList<>();
        processList.stream().forEach(p -> {
            FlowInfo info = new FlowInfo();
            info.setProcessInstanceId(p.getId());
            info.setBusinessKey(p.getBusinessKey());
            info.setName(p.getProcessDefinitionName());
            info.setStartTime(p.getStartTime());
            info.setEndTime(p.getEndTime());
            info.setStartUserId(p.getStartUserId());
            if (p.getEndTime() == null) {
                info.setEnded(false);
                // 查看当前活动任务
                List<Task> tasks = processEngine.getTaskService().createTaskQuery().processInstanceId(p.getId()).list();
                String taskName = "";
                String assignee = "";
                for (Task t : tasks) {
                    taskName += t.getName() + ",";
                    assignee += t.getAssignee() + ",";
                }
                taskName = taskName.substring(0, taskName.length() - 1);
                assignee = assignee.substring(0, assignee.length() - 1);
                info.setCurrentTask(taskName);
                info.setAssignee(assignee);
            } else {
                info.setEnded(true);
            }
            flows.add(info);
        });
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(0);
        rspData.setRows(flows);
        rspData.setTotal(total);
        return rspData;
    }

    private void renderFlow(HttpServletResponse httpServletResponse, List<String> activityIds, List<String> flows, String processDefinitionId)
            throws IOException {
        //获取流程图
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engConfig = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engConfig.getProcessDiagramGenerator();
        @Cleanup InputStream in = diagramGenerator.generateDiagram(
                bpmnModel,
                "png",
                activityIds,
                flows,
                engConfig.getActivityFontName(),
                engConfig.getLabelFontName(),
                engConfig.getAnnotationFontName(),
                engConfig.getClassLoader(),
                1.0,
                true);
        @Cleanup OutputStream out = httpServletResponse.getOutputStream();
        byte[] buf = new byte[1024];
        int length;
        while ((length = in.read(buf)) != -1) {
            out.write(buf, 0, length);
        }
    }
}
